using System;
using System.Collections.Generic;
using System.Text;
using MacomberMap.Common.Components;
using System.Windows.Forms;
using MacomberMap.Common.Database_Interface;
using System.Reflection;
using System.Collections;
using MacomberMap.Common.Internals;

namespace MacomberMap.Common.Events
{
    /// <summary>
    /// This class holds information on an event's value change
    /// </summary>
    public class MM_Event_ValueChange : MM_Event
    {
        #region Variable declarations

        /// <summary>The old value</summary>
        public Object OldValue;

        /// <summary>The new value</summary>
        public Object NewValue;

        /// <summary>The name of the value</summary>
        public String ValueName;

        /// <summary>
        /// The element that changed
        /// </summary>
        public MM_Element BaseElement;
        #endregion

        /// <summary>
        /// Initialize a new event change dialog
        /// </summary>
        /// <param name="BaseElement">The element that had a value changed</param>
        /// <param name="OldValue">The old value</param>
        /// <param name="NewValue">The new value</param>
        /// <param name="ValueName">The name of the value that was changed</param>
        public MM_Event_ValueChange(MM_Element BaseElement, Object OldValue, Object NewValue, String ValueName)
        {
            this.BaseElement = BaseElement;
            this.OldValue = OldValue;
            this.NewValue = NewValue;
            this.ValueName = ValueName;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="OutMenu"></param>
        public override void AddMenuItems(System.Windows.Forms.ContextMenuStrip OutMenu)
        {
            (OutMenu.Items.Add("Updated " + ValueName) as ToolStripMenuItem).Enabled = false;
            if (OldValue == null)
                (OutMenu.Items.Add("Old: ") as ToolStripMenuItem).Enabled = false;
            else
                (OutMenu.Items.Add("Old: " + OldValue.ToString()) as ToolStripMenuItem).Enabled = false;

            if (NewValue == null)
                (OutMenu.Items.Add("New: ") as ToolStripMenuItem).Enabled = false;
            else
                (OutMenu.Items.Add("New: " + NewValue.ToString()) as ToolStripMenuItem).Enabled = false;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>        
        public override ListViewItem BuildListViewItem()
        {
            ListViewItem NewItem = new ListViewItem(ValueName + ": " + BaseElement.ToString());
            NewItem.SubItems.Add(this.EventState.ToString());
            NewItem.SubItems.Add(TimeText);
            NewItem.ImageIndex = EventType.Index;
            return NewItem;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="OutParent"></param>
        public override void DisplayDetails(Control OutParent)
        {
            TreeView tvOut = new TreeView();
            tvOut.Dock = DockStyle.Fill;
            this.AddNodeItem("Element", BaseElement, tvOut.Nodes);
            this.AddNodeItem("Value", ValueName, tvOut.Nodes);
            this.AddNodeItem("Old", OldValue, tvOut.Nodes);
            this.AddNodeItem("New", NewValue, tvOut.Nodes);
            tvOut.Nodes[0].EnsureVisible();
            OutParent.Controls.Add(tvOut);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="lvItem"></param>
        public override void UpdateListViewItem(ListViewItem lvItem)
        {
            lvItem.SubItems[0].Text = ValueName + ": " + BaseElement.ToString();
            lvItem.SubItems[1].Text = EventState.ToString();
            lvItem.SubItems[2].Text = TimeText;
        }

        /// <summary>
        /// Approve the change to the system for this event
        /// </summary>
        /// <param name="ConnectedDatabases">The databases with which the event viewer is connected</param>
        public void ApproveChange(MM_Database[] ConnectedDatabases)
        {          
            //First, update our value
            if (ValueName == "TEID")
            {
                BaseElement.TEID = (UInt64)NewValue;

                //Make the change internally
                if (MM_Repository.MismatchedTEIDs.ContainsKey((UInt64)NewValue) && MM_Repository.MismatchedTEIDs[(UInt64)NewValue] == BaseElement)
                    MM_Repository.MismatchedTEIDs.Remove((UInt64)NewValue);
                if (MM_Repository.TEIDs.ContainsKey((UInt64)OldValue) && MM_Repository.TEIDs[(UInt64)OldValue] == BaseElement)
                    MM_Repository.TEIDs.Remove((UInt64)OldValue);
                MM_Repository.TEIDs.Add((UInt64)NewValue, BaseElement);
            }
            else
                foreach (MemberInfo mI in BaseElement.GetType().GetMember(ValueName))
                {
                    Object inObject = null;
                    if (mI is FieldInfo)
                        inObject = (mI as FieldInfo).GetValue(BaseElement);
                    else if (mI is PropertyInfo)
                        inObject = (mI as PropertyInfo).GetValue(BaseElement, null);

                    //If our object is a list, we may need to add or remove it.
                    /*if (inObject is IList)
                    {
                        if (NewValue == null)
                            (inObject as IList).Remove(OldValue);
                        else if (OldValue == null)
                            (inObject as IList).Add(NewValue);
                    }
                    else */
                    if (mI is FieldInfo)
                        (mI as FieldInfo).SetValue(BaseElement, NewValue);
                    else if (mI is PropertyInfo)
                        (mI as PropertyInfo).SetValue(BaseElement, NewValue, null);
                }

            //Go through, and update accordingly.
            foreach (MM_Database Db in ConnectedDatabases)
                if (Db is MM_Database_Oracle)
                    if (ValueName == "TEID")
                        (Db as MM_Database_Oracle).UpdateTEID(BaseElement, (UInt64)OldValue, (UInt64)NewValue);
                    else
                        (Db as MM_Database_Oracle).UpdateElement(BaseElement, this.ValueName, NewValue);
        }

        /// <summary>
        /// Compare two value changes
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override int CompareTo(object obj)
        {
            int ValueTest = ValueName.CompareTo((obj as MM_Event_ValueChange).ValueName);
            if (ValueTest == 0)
                return BaseElement.CompareTo((obj as MM_Event_ValueChange).BaseElement);
            else
                return ValueTest;
        }
    }
}
